﻿
using System;
using System.IO;
using System.Text;
using CuteAnt.IO;
using Ionic.BZip2;
using Ionic.Zip;
using Ionic.Zlib;

namespace CuteAnt.Zip
{

	public class ZipIonic
	{

		#region -- method ZipPackFile --

		public static void ZipPackFile(String zipedFile, String fileToZip)
		{
			ZipPackFile(zipedFile, fileToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFile(String zipedFile, String fileToZip, CompressionLevel compressionLevel)
		{
			ZipPackFile(zipedFile, fileToZip, compressionLevel, null);
		}

		public static void ZipPackFile(String zipedFile, String fileToZip, String password)
		{
			ZipPackFile(zipedFile, fileToZip, CompressionLevel.Default, password);
		}

		public static void ZipPackFile(String zipedFile, String fileToZip, CompressionLevel compressionLevel, String password)
		{
			if (zipedFile.IsNullOrWhiteSpace()) { return; }
			fileToZip = FileHelper.FileExists(fileToZip);
			if (fileToZip.IsNullOrWhiteSpace()) { return; }

			try
			{

				using (ZipFile zip = new ZipFile(Encoding.UTF8))
				{
					zip.CompressionLevel = compressionLevel;
					zip.Password = password;
					zip.AddFile(fileToZip);
					zip.Save(zipedFile);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		public static void ZipPackFiles(String zipedFile, String[] filesToZip)
		{
			ZipPackFiles(zipedFile, filesToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFiles(String zipedFile, String[] filesToZip, CompressionLevel compressionLevel)
		{
			ZipPackFiles(zipedFile, filesToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFiles(String zipedFile, String[] filesToZip, String password)
		{
			ZipPackFiles(zipedFile, filesToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFiles(String zipedFile, String[] filesToZip, CompressionLevel compressionLevel, String password)
		{
			if (zipedFile.IsNullOrWhiteSpace()) { return; }
			if (filesToZip == null) { return; }

			try
			{

				using (ZipFile zip = new ZipFile())
				{
					zip.CompressionLevel = compressionLevel;
					zip.Password = password;
					//String file;
					//for (Int32 idx = 0; idx < filesToZip.Length; idx++)
					//{
					//  file = FileHelper.FileExists(filesToZip[idx]);
					//  if (!file.IsNullOrWhiteSpace())
					//  {
					//    zip.AddFile(file);
					//  }
					//}
					zip.AddFiles(filesToZip);
					zip.Save(zipedFile);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		#endregion

		#region -- method ZipPackFolder --

		public static void ZipPackFolder(String zipedFile, String folderToZip)
		{
			ZipPackFolder(zipedFile, folderToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFolder(String zipedFile, String folderToZip, CompressionLevel compressionLevel)
		{
			ZipPackFolder(zipedFile, folderToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFolder(String zipedFile, String folderToZip, String password)
		{
			ZipPackFolder(zipedFile, folderToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFolder(String zipedFile, String folderToZip, CompressionLevel compressionLevel, String password)
		{
			if (zipedFile.IsNullOrWhiteSpace()) { return; }
			folderToZip = FileHelper.DirectoryExists(folderToZip);
			if (folderToZip.IsNullOrWhiteSpace()) { return; }

			try
			{

				using (ZipFile zip = new ZipFile(Encoding.UTF8))
				{
					zip.CompressionLevel = compressionLevel;
					zip.Password = password;
					zip.AddDirectory(folderToZip);
					zip.Save(zipedFile);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		public static void ZipPackFolders(String zipedFile, String[] foldersToZip)
		{
			ZipPackFolders(zipedFile, foldersToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFolders(String zipedFile, String[] foldersToZip, CompressionLevel compressionLevel)
		{
			ZipPackFolders(zipedFile, foldersToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFolders(String zipedFile, String[] foldersToZip, String password)
		{
			ZipPackFolders(zipedFile, foldersToZip, CompressionLevel.Default, null);
		}

		public static void ZipPackFolders(String zipedFile, String[] foldersToZip, CompressionLevel compressionLevel, String password)
		{
			if (zipedFile.IsNullOrWhiteSpace()) { return; }
			if (foldersToZip == null) { return; }

			try
			{

				using (ZipFile zip = new ZipFile())
				{
					zip.CompressionLevel = compressionLevel;
					zip.Password = password;
					String folder;

					for (Int32 idx = 0; idx < foldersToZip.Length; idx++)
					{
						folder = FileHelper.DirectoryExists(foldersToZip[idx]);
						if (!folder.IsNullOrWhiteSpace())
						{
							zip.AddDirectory(folder);
						}
					}
					zip.Save(zipedFile);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		#endregion

		#region -- BZip2 Compress / Decompress --

		public static void BZip2Compress(String zipedFile, String fileToZip)
		{
			BZip2Compress(zipedFile, fileToZip, 9);
		}

		public static void BZip2Compress(String zipedFile, String fileToZip, Int32 bufferSize)
		{
			if (zipedFile.IsNullOrWhiteSpace()) { return; }
			fileToZip = FileHelper.FileExists(fileToZip);
			if (fileToZip.IsNullOrWhiteSpace()) { return; }

			try
			{

				using (Stream input = File.OpenRead(fileToZip), output = File.Create(zipedFile))
				{
					BZip2Compress(input, output, bufferSize, false);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		public static void BZip2Compress(Stream inStream, Stream outStream, Int32 bufferSize, Boolean isStreamOwner)
		{
			if (inStream == null || outStream == null)
			{
				throw new Exception("Null Stream");
			}

			try
			{

				using (Stream compressor = new ParallelBZip2OutputStream(outStream))
				{
					Pump(inStream, compressor, bufferSize);
				}
			}
			catch (Exception ex) { ex = null; }
			finally
			{
				if (isStreamOwner)
				{
					inStream.Close();
					// outStream is closed by the BZip2OutputStream if stream owner
					inStream.Close();
				}
			}
		}

		public static void BZip2Decompress(String zipFile, String targetFile)
		{
			BZip2Decompress(zipFile, targetFile, 4096);
		}

		public static void BZip2Decompress(String zipFile, String targetFile, Int32 bufferSize)
		{
			if (targetFile.IsNullOrWhiteSpace()) { return; }
			zipFile = FileHelper.FileExists(zipFile);
			if (zipFile.IsNullOrWhiteSpace()) { return; }

			try
			{

				using (Stream input = File.OpenRead(zipFile), output = File.Create(targetFile))
				{
					BZip2Decompress(input, output, bufferSize, false);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		public static void BZip2Decompress(Stream inStream, Stream outStream, Int32 bufferSize, Boolean isStreamOwner)
		{
			if (inStream == null || outStream == null)
			{
				throw new Exception("Null Stream");
			}

			try
			{

				using (Stream decompressor = new BZip2InputStream(inStream))
				{
					Pump(decompressor, outStream, bufferSize);
				}
			}
			catch (Exception ex) { ex = null; }
			finally
			{
				if (isStreamOwner)
				{
					inStream.Close();
					// inStream is closed by the BZip2InputStream if stream owner
					outStream.Close();
				}
			}
		}

		#endregion

		#region -- GZip Compress / Decompress --

		public static void GZipCompress(String zipedFile, String fileToZip)
		{
			GZipCompress(zipedFile, fileToZip, 4096);
		}

		public static void GZipCompress(String zipedFile, String fileToZip, Int32 bufferSize)
		{
			if (zipedFile.IsNullOrWhiteSpace()) { return; }
			fileToZip = FileHelper.FileExists(fileToZip);
			if (fileToZip.IsNullOrWhiteSpace()) { return; }

			try
			{

				using (Stream input = File.OpenRead(fileToZip), output = File.Create(zipedFile))
				{
					GZipCompress(input, output, bufferSize, false);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		public static void GZipCompress(Stream inStream, Stream outStream, Int32 bufferSize, Boolean isStreamOwner)
		{
			if (inStream == null || outStream == null)
			{
				throw new Exception("Null Stream");
			}

			try
			{

				using (var compressor = new GZipStream(outStream, CompressionMode.Compress))
				{
					//compressor.FileName = fileToZip;
					//var fi = new FileInfo(fileToZip);
					//compressor.LastModified = fi.LastWriteTime;
					Pump(inStream, compressor, bufferSize);
				}
			}
			catch (Exception ex) { ex = null; }
			finally
			{
				if (isStreamOwner)
				{
					inStream.Close();
					// outStream is closed by the BZip2OutputStream if stream owner
					inStream.Close();
				}
			}
		}

		public static void GZipDecompress(String zipFile, String targetFile)
		{
			GZipDecompress(zipFile, targetFile, 4096);
		}

		public static void GZipDecompress(String zipFile, String targetFile, Int32 bufferSize)
		{
			if (targetFile.IsNullOrWhiteSpace()) { return; }
			zipFile = FileHelper.FileExists(zipFile);
			if (zipFile.IsNullOrWhiteSpace()) { return; }

			try
			{

				using (Stream input = File.OpenRead(zipFile), output = File.Create(targetFile))
				{
					GZipDecompress(input, output, bufferSize, false);
				}
			}
			catch (Exception ex) { ex = null; }
		}

		public static void GZipDecompress(Stream inStream, Stream outStream, Int32 bufferSize, Boolean isStreamOwner)
		{
			if (inStream == null || outStream == null)
			{
				throw new Exception("Null Stream");
			}

			try
			{

				using (var decompressor = new GZipStream(inStream, CompressionMode.Decompress))
				{
					Pump(decompressor, outStream, bufferSize);
				}
			}
			catch (Exception ex) { ex = null; }
			finally
			{
				if (isStreamOwner)
				{
					inStream.Close();
					// inStream is closed by the BZip2InputStream if stream owner
					outStream.Close();
				}
			}
		}

		#endregion

		private static void Pump(Stream src, Stream dest, Int32 bufferSize)
		{
			Byte[] buffer = new Byte[bufferSize];
			Int32 n;

			while ((n = src.Read(buffer, 0, buffer.Length)) > 0)
			{
				dest.Write(buffer, 0, n);
			}
		}
	}
}
